/*
 * @Author: Wangjun
 * @Date: 2023-03-07 14:37:30
 * @LastEditTime: 2023-03-07 14:53:36
 * @LastEditors: Wangjun
 * @Description:
 * @FilePath: \libs\radix\radix_sync.go
 * hnxr
 */
package radix

import (
	"encoding/binary"
	"sync"
)

// 生成32位整数的key
func NewInt32Key(t int64) string {
	key := make([]byte, 4)
	binary.BigEndian.PutUint32(key, uint32(t))
	return string(key)
}

// 生成64位整数的key
func NewInt64Key(t int64) string {
	key := make([]byte, 8)
	binary.BigEndian.PutUint64(key, uint64(t))
	return string(key)
}

type SafeTree[G any] struct {
	t    *Tree[G]
	lock sync.RWMutex
}

// New returns an empty SafeTree
func NewSafeTree[G any]() *SafeTree[G] {
	st := new(SafeTree[G])
	st.t = NewFromMap[G](nil)
	return st
}

// NewFromMap returns a new tree containing the keys
// from an existing map
func NewSafeTreeFromMap[G any](m map[string]*G) *SafeTree[G] {
	st := new(SafeTree[G])
	t := &Tree[G]{root: &node[G]{}}
	for k, v := range m {
		t.Insert(k, v)
	}
	st.t = t
	return st
}

// Len is used to return the number of elements in the tree
func (m *SafeTree[G]) Len() int {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.t.size
}

// Insert is used to add a newentry or update
// an existing entry. Returns true if an existing record is updated.

func (m *SafeTree[G]) Insert(s string, v *G) (*G, bool) {
	m.lock.Lock()
	defer m.lock.Unlock()
	return m.t.Insert(s, v)
}

// Delete is used to delete a key, returning the previous
// value and if it was deleted

func (m *SafeTree[G]) Delete(s string) (*G, bool) {
	m.lock.Lock()
	defer m.lock.Unlock()
	return m.t.Delete(s)
}

// DeletePrefix is used to delete the subtree under a prefix
// Returns how many nodes were deleted
// Use this to delete large subtrees efficiently

func (m *SafeTree[G]) DeletePrefix(s string) int {
	m.lock.Lock()
	defer m.lock.Unlock()
	return m.t.DeletePrefix(s)
}

// Get is used to lookup a specific key, returning
// the value and if it was found

func (m *SafeTree[G]) Get(s string) (*G, bool) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.t.Get(s)
}

// LongestPrefix is like Get, but instead of an
// exact match, it will return the longest prefix match.

func (m *SafeTree[G]) LongestPrefix(s string) (string, *G, bool) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.t.LongestPrefix(s)
}

// Minimum is used to return the minimum value in the tree
func (m *SafeTree[G]) Minimum() (string, *G, bool) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.t.Minimum()
}

// Maximum is used to return the maximum value in the tree
func (m *SafeTree[G]) Maximum() (string, *G, bool) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.t.Maximum()
}

// Walk is used to walk the tree
func (m *SafeTree[G]) Walk(fn WalkFn[G]) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	m.t.Walk(fn)
}

// WalkPrefix is used to walk the tree under a prefix
func (m *SafeTree[G]) WalkPrefix(prefix string, fn WalkFn[G]) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	m.t.WalkPrefix(prefix, fn)
}

// WalkPath is used to walk the tree, but only visiting nodes
// from the root down to a given leaf. Where WalkPrefix walks
// all the entries *under* the given prefix, this walks the
// entries *above* the given prefix.
func (m *SafeTree[G]) WalkPath(path string, fn WalkFn[G]) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	m.t.WalkPath(path, fn)
}

// ToMap is used to walk the tree and convert it into a map
func (m *SafeTree[G]) ToMap() map[string]*G {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.t.ToMap()
}

// ToArray ToMap is used to walk the tree and convert it into a array
func (m *SafeTree[G]) ToArray() (array []*G) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.t.ToArray()
}
